#=============================================================================
#
# 各项目通用的 C/C++ 编译、链接选项
#
#=============================================================================

# Disable in-source builds to prevent source tree corruption.
if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
  message(FATAL_ERROR "FATAL: In-source builds are not allowed. You should create a separate directory for build files.")
endif()

# Only generate Debug and Release configuration types.
set(CMAKE_CONFIGURATION_TYPES Debug Release)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# Bootstap CMake system: setup CMAKE_SYSTEM_NAME and other vars
enable_language(CXX C)

# Determine the platform.
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
  set(OS_MACOSX 1)
  set(OS_POSIX 1)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
  set(OS_LINUX 1)
  set(OS_POSIX 1)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
  set(OS_WINDOWS 1)
endif()

# =============================================================================
# set compiler/linker flags.
if(OS_WINDOWS)
  # /bigobj               = 将该地址容量增加至 4,294,967,296 (2^32)
  # /MP                   = Multiprocess compilation
  # /W4                   = Warning level 4
  # /WX                   = Treat warnings as errors
  # _HAS_AUTO_PTR_ETC     = 恢复 Visual Studio C++17 删除的 auto_ptr
  # _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS = 关闭 C++ 17 DEPRECATION 的警告
  set(COMPILER_FLAGS         "/bigobj /Wv:18 /MP /W4 /WX /D_HAS_AUTO_PTR_ETC=1 /D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS")
  
  # /MDd or /MTd          = Multithreaded debug runtime
  # /Zi                   = Enable program database
  # /Od                   = Disable optimizations
  # /Ob0                  = Disable Inline function
  # /RTC1                 = Enable basic run-time checks
  # /DDEBUG /D_DEBUG"     = This is a debug build
  set(COMPILER_FLAGS_DEBUG   "/MTd /Zi /Od /Ob0 /RTC1 /DDEBUG /D_DEBUG")
  
  # /MD or /MT            = Multithreaded release runtime
  # /O2                   = Optimize for maximum speed
  # /Ob2                  = Inline any suitable function
  # /GF                   = Enable string pooling
  # /DNDEBUG /D_NDEBUG    = Not a debug build
  set(COMPILER_FLAGS_RELEASE "/MT /O2 /Ob2 /GF /DNDEBUG /D_NDEBUG")
  
  # /SUBSYSTEM:CONSOLE    = 显示控制台窗口（便于调试）
  set(LINKER_FLAGS_DEBUG     "/DEBUG /SUBSYSTEM:CONSOLE")
  
  set(LINKER_FLAGS_RELEASE   "")

elseif(OS_LINUX)
  # 使用 ccache 加速 gcc
  find_program(CCACHE_FOUND ccache)
  if(CCACHE_FOUND)
    message("ccache found, use ccache!")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) # Less useful to do it for linking, see edit2
  endif(CCACHE_FOUND)

  set(COMPILER_FLAGS         "-Wall -fPIC -pipe -std=c++20")
  set(COMPILER_FLAGS_DEBUG   "-O0 -ggdb")
  set(COMPILER_FLAGS_RELEASE "")

  # 静态链接
  #set(LINKER_FLAGS "-static")
endif()

# =============================================================================
# Merge compiler/linker flags.
# 合并时，如果有重复的选项，经过试验，会使用后面的选项（即上面的设置项）
set(CMAKE_C_FLAGS                     "${CMAKE_C_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG               "${CMAKE_C_FLAGS_DEBUG} ${COMPILER_FLAGS_DEBUG}")
set(CMAKE_C_FLAGS_RELEASE             "${CMAKE_C_FLAGS_RELEASE} ${COMPILER_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS                   "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG             "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_FLAGS_DEBUG}")
set(CMAKE_CXX_FLAGS_RELEASE           "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_FLAGS_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS            "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG      "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINKER_FLAGS_DEBUG}")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE    "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS         "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG   "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${LINKER_FLAGS_DEBUG}")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")

# 使用内部模块
macro(use_module ag_project_name ag_module_name)
  target_compile_definitions(${ag_project_name} PRIVATE USE_MODULE_${ag_module_name})

  if(${ag_module_name}_SOURCE_DIR)
    target_include_directories(${ag_project_name} PRIVATE ${${ag_module_name}_SOURCE_DIR}/include)
  else()
    target_include_directories(${ag_project_name} PRIVATE  ${CMAKE_INSTALL_PREFIX}/include/${ag_module_name})
    target_link_directories(${ag_project_name} PRIVATE ${CMAKE_INSTALL_PREFIX}/lib)
  endif()
  target_link_libraries(${ag_project_name} PRIVATE ${ag_module_name})
endmacro(use_module)